uni-app-用户角色更新问题(uni-popup关闭二次触发 @change)

2025-10-01

问题是这样的,在喵喵CRM权限管理模块里,可以修改用户的角色。

但是用户编辑时候,点开角色复选框,选择角色,确认后,用户的角色并没有变化。排查了后端问题之后,初步判断问题应该就是在前端。

因为个人没有系统学习uni-app,主要是AI在写,我来提修改意见,所以这个bug的修复非常折磨。在经历了Gemini和GPT双双折戟后,颇为郁闷。大晚上纠结半天,睡不着,越想越不对,这个问题明明不严重,怎么可能解决不了呢?遂亲自上手,来整体梳理一下。

流程梳理

首先入口代码如下,调用了一个openRoleMultiPicker

<view class="picker-value-display" @click="openRoleMultiPicker">
  {{ userSelectedGroupNames.length ? userSelectedGroupNames.join(', ') : '请选择角色' }}
</view>

我们来看下openRoleMultiPicker

    // 打开多选角色选择器
    openRoleMultiPicker() {
      this.$refs.roleMultiPicker.open();
    },

打开自定义的 user-role-multi-picker 组件。这个组件是独立出去写得,等下在排查,我觉得问题在确认的接收那儿。我们先看下监听代码:

<user-role-multi-picker
  ref="roleMultiPicker"
  :value="userFormData.groups_write"
  :options="availableGroups"
  title="选择用户角色"
  @change="onRoleMultiPickerChange"
></user-role-multi-picker>

也就是说,user-role-multi-picker 子组件在确认选择时,应该发送一个 change 事件,并传回,change事件代码如下:

onRoleMultiPickerChange(selectedIds) {
  const normalized = Array.isArray(selectedIds)
    ? selectedIds.map(v => Number(v))
    : [];
  this.userFormData.groups_write = normalized;
},

这里接收传回来的 selectedIds,存进 userFormData.groups_write。然后有个计算,确认后表单现实的如下:

userSelectedGroupNames() {
  return (this.userFormData.groups_write || [])
    .map(id => {
      const group = this.availableGroups.find(g => String(g.id) === String(id));
      return group ? group.name : '';
    })
    .filter(Boolean);
},

考虑到数据库在修改后同样没有更新,所以初步判断是存进 userFormData.groups_write这儿可能就出了问题,很有可能是数据格式的问题。

初步分析

上述代码不太明白,但是好歹功能是清楚了。如果是数据格式出了问题,大概率是存进 userFormData.groups_write是,不认或者识别错误。这儿先贴一个示例,也就是用户数据到底什么样:

    {
        "id": 1,
        "username": "13989",
        "email": "1398943200@qq.com",
        "first_name": "小阳",
        "last_name": "沈",
        "groups_read": [
            {
                "id": 1,
                "name": "管理员"
            }
        ]
    },

当然,这是GET的数据格式。但是实际上写入的是group_write,PATCH 示例数据如下:

{
    "groups_write": [1]
}

所以,两种可能,第一种是读的时候是groups_read,写的时候是groups_write,可能传递的参数名不一样,所以获取不了。当然,上述仅限本人粗浅的小白理解。继续往下排查,看看情况。第二种是写个格式错了,比如单纯是1,而不是[1]。

验证

测试了一下,不是上述两种情况。不过在输出数据时候,发现一个很有趣的点,onRoleMultiPickerChange 被触发两轮,而第一次触发时返回的数是对的,[2],但是第二次不知道怎么回事,获取了一个很异常的东西。

02:19:47.397 原始参数: [ 2 ] 类型: object at pages\permission\permission.uvue:335
02:19:47.397 原始参数: [ 2 ] 类型: object at pages\permission\permission.uvue:335
02:19:47.397 原始参数: [ 2 ] 类型: object at pages\permission\permission.uvue:335
02:19:47.397 转换值: 2 -> 2 at pages\permission\permission.uvue:339
02:19:47.397 转换值: 2 -> 2 at pages\permission\permission.uvue:339
02:19:47.397 转换值: 2 -> 2 at pages\permission\permission.uvue:339
02:19:47.408 转换结果: [ 2 ] at pages\permission\permission.uvue:344
02:19:47.408 转换结果: [ 2 ] at pages\permission\permission.uvue:344
02:19:47.408 转换结果: [ 2 ] at pages\permission\permission.uvue:344
02:19:47.408 调用堆栈 at pages\permission\permission.uvue:345
02:19:47.408 调用堆栈 at pages\permission\permission.uvue:345
02:19:47.408 调用堆栈 at pages\permission\permission.uvue:345
02:19:47.408 console.groupEnd at pages\permission\permission.uvue:346
02:19:47.408 console.groupEnd at pages\permission\permission.uvue:346
02:19:47.408 console.groupEnd at pages\permission\permission.uvue:346
02:19:47.408 onRoleMultiPickerChange 触发 at pages\permission\permission.uvue:334
02:19:47.408 onRoleMultiPickerChange 触发 at pages\permission\permission.uvue:334
02:19:47.408 onRoleMultiPickerChange 触发 at pages\permission\permission.uvue:334
02:19:47.420 原始参数: ‍[⁠UTSJSONObject2⁠]‍ {show: false, type: "center"} 类型: object at pages\permission\permission.uvue:335
02:19:47.420 原始参数: ‍[⁠UTSJSONObject2⁠]‍ {show: false, type: "center"} 类型: object at pages\permission\permission.uvue:335
02:19:47.420 原始参数: ‍[⁠UTSJSONObject2⁠]‍ {show: false, type: "center"} 类型: object at pages\permission\permission.uvue:335
02:19:47.420 转换结果: [ ⁠...⁠ ] at pages\permission\permission.uvue:344
02:19:47.420 转换结果: [ ⁠...⁠ ] at pages\permission\permission.uvue:344
02:19:47.420 转换结果: [ ⁠...⁠ ] at pages\permission\permission.uvue:344
02:19:47.420 调用堆栈 at pages\permission\permission.uvue:345
02:19:47.420 调用堆栈 at pages\permission\permission.uvue:345
02:19:47.420 调用堆栈 at pages\permission\permission.uvue:345

问了下GPT,onRoleMultiPickerChange触发了两次

一次是 UserRoleMultiPicker 子组件选择完返回的 [2](正常)

第二次是 uni-popup 关闭的时候,冒泡又触发了一次 @change,参数变成了 {show: false, type: 'center'} 这种对象,结果代码里还当数组去处理 → 就把数据冲掉了。

TMD、TMD、TMD,为什么有这么傻逼的事情!!!!现在凌晨两点四十分,太棒了。

最后onRoleMultiPickerChange 加入一个判断,非常规数值不用管,就解决问题了:

  if (!Array.isArray(selectedIds)) {
    return;
  }

← 返回